(***********************************************************************)
(*                                                                     *)
(*  Programowanie Funkcyjne                                            *)
(*  Wydział MiMUW                                                      *)
(*                                                                     *)
(*  Marcin Walas                                                       *)
(*  262460                                                             *)
(*                                                                     *)
(***********************************************************************)
(*

    Tutaj znajduje się konkretna implementacja modulow dla 
    gry w Warcaby
*)

(* external *)
open OImages;;
open Printf;;

(* internal *)

open Gui;;

module type BOARD_SIGNATURE =
    (*
        abstrakcja od implementacji planszy
    *)
    sig
        type field_type
        type board_type = Board of field_type list list

        type piece_type = field_type*int*int*bool (* Figura wraz z polozeniem *)    
        type pieces_type = (piece_type list) * (piece_type list)

        type human_state_type

        type state_type 
(*
        {
            board : board_type;
            pieces : pieces_type;
            human_state : human_state_type;
        } 

*)
                (* caly status gry w danym 
                momencie, jest podawany do funckji modulu jako argument tego
                wlasnie typu *)

        val empty_board : board_type

        val get_at : state_type -> int -> int -> field_type

    end;;


module type GAME_INSTANCE = 
(*
    To dostarcza konkretne instancje funkcji dla konkretnego rodzaju gry
*)
    sig
        include BOARD_SIGNATURE

        type move_type = piece_type*(int*int)

        val get_rgb_for_type : field_type -> bool -> OImages.rgb24 (* odwzorowanie z 
                typów na jakieś wartości rgb *)

        val start_board : board_type
        val start_state : unit -> state_type

        val check_move : state_type -> move_type -> bool
        val make_move : state_type -> move_type -> state_type
        val put_piece : state_type -> piece_type -> state_type

        (* For iteration through pieces on board representation *)
        val iter_through_pieces : state_type -> (int -> int -> OImages.rgb24 -> unit) -> unit

        (* Obsługa ludzi *)
        val click_handler : state_type -> bool -> int -> int -> bool*state_type
    end;;


module type GAME_TYPE = 
    functor(Game : GAME_INSTANCE) ->
(* 
   To jest taki framework do rozgrywania gier na planszy o wymiarach 8x8 
   o grze nalezy założyć, że na jednym polu może być co najwyżej jedna
   figura (każde pole jest dokładnie jednego typu).

   Jeśli chcemy zaimplementować grę, w której tak naprawdę nie wykonuje się
   ruchów - to znaczy do wykonania posunięcia wystarczy podać punkt
   docelowy i jakiś inny parametr to wystarczy odpowiednio zignorować
   argument w check_move.

   W grze domyslnie wystepuja 2 gracze - jeden jest uznawany za czerwonego
   drugi z bialego.
*)
    sig
        type field_type = Game.field_type (* typ pola, jakas figura lub po 
                prostu rysunek, który ma się tam wyświetlić *)
        type state_type = Game.state_type
        type pieces_type 
        type move_type = Game.move_type

        val make_move : state_type -> move_type -> state_type (* to powinno 
                wołać do Gui w celu odświeżenia planszy *)
            
        val redraw : state_type -> unit (* przerysowuje to po prostu jeszcze
                raz planszę do gry w aktualnym stanie *)

        val start_state : unit -> state_type

        val click_handler : state_type -> bool -> int -> int -> bool*state_type
    end;;

module GameAbstract : GAME_TYPE = 
    (* Deklaracja funktora tworzącego gry *)
    functor (Game : GAME_INSTANCE) ->
    struct
        type field_type = Game.field_type
        type state_type = Game.state_type
        type pieces_type = Game.pieces_type
        type move_type = Game.move_type

        exception IllegalMove

        let redraw (state:state_type) =
            eprintf "GAME NOTICE : redraw called\n";
            flush stderr;

            let _ = Gui.GuiManager.redraw_background () in
            let _ = Game.iter_through_pieces (state) (fun (x:int) (y:int) (rgb:OImages.rgb24) -> Gui.GuiManager.draw_bitmap x y rgb) in 
            ();;
        
        let make_move (state:state_type) (move:move_type) =
            let state =  Game.make_move state move in
            let _ = redraw state in
            state;;

        let start_state = Game.start_state;;

        let click_handler x y = Game.click_handler x y;;
    end;;



       







